package org.example.interceptor;

import cn.lingyangwl.framework.core.response.Resp;
import cn.lingyangwl.framework.core.utils.servlet.ServletUtils;
import org.apache.commons.lang3.StringUtils;
import org.example.annotation.ApiIdempotent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author shenguangyang
 */
@Component
public class ApiIdempotentInterceptor implements HandlerInterceptor {
    private static final Logger log = LoggerFactory.getLogger(ApiIdempotentInterceptor.class);
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        // 跨域时会首先发送一个option请求，这里我们给option请求直接返回正常状态
        if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
            response.setStatus(HttpStatus.OK.value());
            return false;
        }

        // 判断是否需要接口幂等性校验
        if (isCheckIdempotent(handler)) {
            String requestId = request.getHeader("request-id");
            // 如果不存在就返回false, 说明是重复调用
            if (StringUtils.isEmpty(requestId)) {
                ServletUtils.writeJson(Resp.fail("参数缺失"));
                return false;
            }
            // 否则就存在, 存在则把redis里删除token
            if (Boolean.FALSE.equals(stringRedisTemplate.delete(requestId))) {
                // 如果requestId没有值, 则表示不是第一次调用, 是重复调用
                ServletUtils.writeJson(Resp.fail("重复提交"));
                return false;
            }
        }

        return true;
    }

    /**
     * 是否幂等
     */
    public boolean isCheckIdempotent(Object handler) {
        if (handler == null) {
            return true;
        }

        if (!(handler instanceof HandlerMethod)) {
            return false;
        }

        // 必须强转为HandlerMethod
        HandlerMethod handlerMethod = (HandlerMethod) handler;

        // 判断方法上是否有打该注解 || 判断类上是否有打该注解
        return handlerMethod.getMethod().isAnnotationPresent(ApiIdempotent.class) || handlerMethod.getBeanType().isAnnotationPresent(ApiIdempotent.class);
    }
}
